package viewer;

import javax.swing.*;
import javax.swing.event.*;

import model.GeometryModel3D;

import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;

public class RoffObserverFrame extends JFrame implements ActionListener, ChangeListener {

    private RoffViewPanel vp;
    private ActionListener al;
    private boolean antialiasingOn;

    public RoffObserverFrame(ActionListener al) {
        super("RoffView Observer");
        this.al = al;
        antialiasingOn = false;

        JMenuBar menubar = new JMenuBar();
        JMenu menu = new JMenu("File");
        menu.setMnemonic(KeyEvent.VK_F);
        JMenuItem menuItem;

        menuItem = new JMenuItem("Close");
        menuItem.setActionCommand("CLOSE");
        menuItem.setMnemonic(KeyEvent.VK_C);
        menuItem.addActionListener(this);
        menu.add(menuItem);

        menubar.add(menu);

        menu = new JMenu("View");
        menu.setMnemonic(KeyEvent.VK_V);

        menuItem = new JMenuItem("Set View Parameters...");
        menuItem.setActionCommand("V_SETVIEW");
        menuItem.setMnemonic(KeyEvent.VK_V);
        menuItem.addActionListener(this);
        menu.add(menuItem);

        menuItem = new JMenuItem("Set to Default View");
        menuItem.setActionCommand("V_SETDEFAULT");
        menuItem.setMnemonic(KeyEvent.VK_D);
        menuItem.addActionListener(this);
        menu.add(menuItem);

        menu.addSeparator();

        ButtonGroup bg = new ButtonGroup();

        JRadioButtonMenuItem rbmenuItem;
        rbmenuItem = new JRadioButtonMenuItem("Wireframe", true);
        rbmenuItem.setActionCommand("V_WIRE");
        rbmenuItem.setMnemonic(KeyEvent.VK_W);
        rbmenuItem.addActionListener(this);
        bg.add(rbmenuItem);
        menu.add(rbmenuItem);

        rbmenuItem = new JRadioButtonMenuItem("Wireframe w/o Hidden Lines", true);
        rbmenuItem.setActionCommand("V_WIRE_NOHID");
        rbmenuItem.setMnemonic(KeyEvent.VK_H);
        rbmenuItem.addActionListener(this);
        bg.add(rbmenuItem);
        menu.add(rbmenuItem);

        rbmenuItem = new JRadioButtonMenuItem("Shaded");
        rbmenuItem.setActionCommand("V_SOLID");
        rbmenuItem.setMnemonic(KeyEvent.VK_S);
        rbmenuItem.addActionListener(this);
        bg.add(rbmenuItem);
        menu.add(rbmenuItem);

        rbmenuItem = new JRadioButtonMenuItem("Points");
        rbmenuItem.setActionCommand("V_POINTS");
        rbmenuItem.setMnemonic(KeyEvent.VK_P);
        rbmenuItem.addActionListener(this);
        bg.add(rbmenuItem);
        menu.add(rbmenuItem);

        menu.addSeparator();

        bg = new ButtonGroup();

        rbmenuItem = new JRadioButtonMenuItem("Normal Lines", true);
        rbmenuItem.setActionCommand("V_NORMAL");
        rbmenuItem.setMnemonic(KeyEvent.VK_N);
        rbmenuItem.addActionListener(this);
        bg.add(rbmenuItem);
        menu.add(rbmenuItem);

        rbmenuItem = new JRadioButtonMenuItem("Anti-aliased Lines", true);
        rbmenuItem.setActionCommand("V_ANTIALIAS");
        rbmenuItem.setMnemonic(KeyEvent.VK_A);
        rbmenuItem.addActionListener(this);
        bg.add(rbmenuItem);
        menu.add(rbmenuItem);

        menubar.add(menu);

        menu = new JMenu("Tools");
        menu.setMnemonic(KeyEvent.VK_T);

        menuItem = new JMenuItem("Set Background Color");
        menuItem.setActionCommand("T_BGCOLOR");
        menuItem.setMnemonic(KeyEvent.VK_B);
        menuItem.addActionListener(this);
        menu.add(menuItem);

        menuItem = new JMenuItem("Set Surface and Lighting Properties");
        menuItem.setActionCommand("T_LIGHTING");
        menuItem.setMnemonic(KeyEvent.VK_L);
        menuItem.addActionListener(this);
        menu.add(menuItem);

        menubar.add(menu);

        this.setJMenuBar(menubar);

        vp = new RoffViewPanel();
        vp.setOff(new GeometryModel3D());

        this.getContentPane().add(vp, BorderLayout.CENTER);

        this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
        this.addWindowListener(new WindowAdapter() {
                                   public void windowClosing(WindowEvent e) {
                                       closeHandler();
                                   }
                               });
        this.pack();
    }

    public void actionPerformed(ActionEvent e) {

        String action = e.getActionCommand();
        
        if (action.equals("CLOSE")) {
            closeHandler();
        } else if (action.equals("V_SETDEFAULT")) {
            setDefaultPerspective();
        } else if (action.equals("V_SETVIEW")) {
            changeView();
        } else if (action.equals("V_WIRE")) {
            if (antialiasingOn) {
                vp.setViewingStyle(RoffViewPanel.VIEW_WIREFRAME_AA);
            } else {
                vp.setViewingStyle(RoffViewPanel.VIEW_WIREFRAME);
            }
        } else if (action.equals("V_WIRE_NOHID")) {
            if (antialiasingOn) {
                vp.setViewingStyle(RoffViewPanel.VIEW_WIREFRAME_NOHIDDENLINES_AA);
            } else {
                vp.setViewingStyle(RoffViewPanel.VIEW_WIREFRAME_NOHIDDENLINES);
            }
        } else if (action.equals("V_SOLID")) {
            vp.setViewingStyle(RoffViewPanel.VIEW_SOLID);
        } else if (action.equals("V_POINTS")) {
            vp.setViewingStyle(RoffViewPanel.VIEW_POINTS);
        } else if (action.equals("T_BGCOLOR")) {
            changeBackground();
        } else if (action.equals("T_LIGHTING")) {
            changeLighting();
        } else if (action.equals("V_NORMAL")) {
            antialiasingOn = false;
            if (vp.getViewingStyle() == RoffViewPanel.VIEW_WIREFRAME_AA) {
                vp.setViewingStyle(RoffViewPanel.VIEW_WIREFRAME);
            } else if (vp.getViewingStyle() == RoffViewPanel.VIEW_WIREFRAME_NOHIDDENLINES_AA) {
                vp.setViewingStyle(RoffViewPanel.VIEW_WIREFRAME_NOHIDDENLINES);
            }
        } else if (action.equals("V_ANTIALIAS")) {
            antialiasingOn = true;
            if (vp.getViewingStyle() == RoffViewPanel.VIEW_WIREFRAME) {
                vp.setViewingStyle(RoffViewPanel.VIEW_WIREFRAME_AA);
            } else if (vp.getViewingStyle() == RoffViewPanel.VIEW_WIREFRAME_NOHIDDENLINES) {
                vp.setViewingStyle(RoffViewPanel.VIEW_WIREFRAME_NOHIDDENLINES_AA);
            }
        }
    }

    public void setDefaultPerspective() {
        vp.setDefaultPerspective();
    }

    private void closeHandler() {
        al.actionPerformed(new ActionEvent(this, 0, "OBSERVER_CLOSED"));
    }

    private void changeBackground() {
        Color newColor = JColorChooser.showDialog(this, "Choose Background Color", vp.getBackgroundColor());
        if (newColor != null) {
            vp.setBackgroundColor(newColor);
        }
    }

    private void changeLighting() {
        RoffLightingPanel rlp = new RoffLightingPanel(new RoffPhong(vp.getLightingModel()));

        int option = JOptionPane.showConfirmDialog(this,
                                      rlp,
                                      "Surface and Lighting Properties",
                                      JOptionPane.OK_CANCEL_OPTION,
                                      JOptionPane.PLAIN_MESSAGE
                                      );
        if (option == JOptionPane.OK_OPTION) {
            vp.setLightingModel(rlp.getLightingModel());
            vp.fullPaint();
        }
    }

    private void changeView() {
        RoffPerspective perspec = vp.getPerspective();
        RoffViewParameterPanel rvpp = new RoffViewParameterPanel(perspec.getAt(),
                                                                 perspec.getFrom(),
                                                                 perspec.getUp(),
                                                                 perspec.getAngle()
                                                                );

        int option = JOptionPane.showConfirmDialog(this,
                                      rvpp,
                                      "Viewing Space Parameters",
                                      JOptionPane.OK_CANCEL_OPTION,
                                      JOptionPane.PLAIN_MESSAGE
                                      );
        if (option == JOptionPane.OK_OPTION) {
            perspec.setAt(rvpp.getAt());
            perspec.setFrom(rvpp.getFrom());
            perspec.setUp(rvpp.getUp());
            perspec.setAngle(rvpp.getAngle());
            vp.fullPaint();
        }
    }

    public void setOff(GeometryModel3D newOff) {
        vp.setOff(newOff);
        vp.fullPaint();
    }

    public void setObservedPerspective(RoffPerspective perspec) {
        perspec.setChangeListener(this);
        vp.setObservedPerspective(perspec);
        vp.setDefaultPerspective();
    }

    public void stateChanged(ChangeEvent ce) {
         vp.fullPaint();
    }
}